/**
 * 数美SDK完整Hook脚本
 * 
 * 功能:
 * 1. Hook AES加密函数，捕获密钥和IV
 * 2. Hook zlib压缩函数，查看压缩参数
 * 3. Hook Base64编码，查看编码数据
 * 4. 保存所有关键数据到文件
 * 
 * 使用方法:
 * frida -U -f <包名> -l hook_shumei.js --no-pause
 * 
 * 或者attach到运行中的进程:
 * frida -U <包名> -l hook_shumei.js
 */

console.log("\n" + "=".repeat(80));
console.log("数美SDK Hook脚本");
console.log("=".repeat(80));

// 工具函数
function bufferToHex(buffer) {
    if (!buffer) return "null";
    return Array.from(new Uint8Array(buffer))
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');
}

function saveToFile(filename, content) {
    try {
        var file = new File("/sdcard/" + filename, "a");
        file.write(content + "\n");
        file.close();
        console.log("[+] 已保存到: /sdcard/" + filename);
    } catch (e) {
        console.log("[-] 保存文件失败: " + e);
    }
}

// 查找 libsmsdk.so
var libsmsdk = null;

function findLibrary() {
    var modules = Process.enumerateModules();
    for (var i = 0; i < modules.length; i++) {
        if (modules[i].name.indexOf("libsmsdk") !== -1) {
            libsmsdk = modules[i];
            console.log("[+] 找到库: " + libsmsdk.name);
            console.log("    基地址: " + libsmsdk.base);
            console.log("    大小: 0x" + libsmsdk.size.toString(16));
            return true;
        }
    }
    return false;
}

// 等待库加载
var checkInterval = setInterval(function() {
    if (findLibrary()) {
        clearInterval(checkInterval);
        startHook();
    }
}, 100);

setTimeout(function() {
    clearInterval(checkInterval);
    if (!libsmsdk) {
        console.log("[-] 超时：未找到 libsmsdk.so");
        console.log("[*] 提示：请确保应用已加载数美SDK");
    }
}, 5000);

function startHook() {
    console.log("\n" + "=".repeat(80));
    console.log("开始Hook关键函数");
    console.log("=".repeat(80));
    
    // ========== Hook 1: AES加密函数 (sub_4AAE4) ==========
    try {
        var aes_addr = libsmsdk.base.add(0x4AAE4);
        console.log("\n[+] Hook AES加密函数: " + aes_addr);
        
        Interceptor.attach(aes_addr, {
            onEnter: function(args) {
                console.log("\n" + "=".repeat(80));
                console.log("【AES加密】调用");
                console.log("=".repeat(80));
                
                // 参数解析
                var dataPtr = args[0];
                var dataLen = args[1].toInt32();
                var outputPtr = args[2];
                var keyPtr = args[3];
                var unknownArg = args[4];
                var ivPtr = args[5];
                
                console.log("数据指针: " + dataPtr);
                console.log("数据长度: " + dataLen + " 字节");
                console.log("输出指针: " + outputPtr);
                console.log("密钥指针: " + keyPtr);
                console.log("IV指针: " + ivPtr);
                
                // 读取密钥（32字节）
                try {
                    this.key = Memory.readByteArray(keyPtr, 32);
                    var keyHex = bufferToHex(this.key);
                    console.log("\n🔑 密钥 (32字节):");
                    console.log(keyHex);
                    console.log(hexdump(keyPtr, {length: 32, ansi: true}));
                    
                    // 保存密钥
                    saveToFile("shumei_keys.txt", "=".repeat(80));
                    saveToFile("shumei_keys.txt", "时间: " + new Date().toISOString());
                    saveToFile("shumei_keys.txt", "密钥: " + keyHex);
                } catch (e) {
                    console.log("[-] 读取密钥失败: " + e);
                }
                
                // 读取IV（16字节）
                try {
                    this.iv = Memory.readByteArray(ivPtr, 16);
                    var ivHex = bufferToHex(this.iv);
                    console.log("\n🔐 IV (16字节):");
                    console.log(ivHex);
                    console.log(hexdump(ivPtr, {length: 16, ansi: true}));
                    
                    // 保存IV
                    saveToFile("shumei_keys.txt", "IV:   " + ivHex);
                } catch (e) {
                    console.log("[-] 读取IV失败: " + e);
                }
                
                // 读取原始数据（限制最大256字节显示）
                try {
                    if (dataLen > 0 && dataLen < 100000) {
                        var displayLen = Math.min(dataLen, 256);
                        this.data = Memory.readByteArray(dataPtr, dataLen);
                        console.log("\n📄 原始数据 (" + dataLen + " 字节，显示前" + displayLen + "字节):");
                        console.log(hexdump(dataPtr, {length: displayLen, ansi: true}));
                        
                        // 尝试解析为文本
                        try {
                            var text = Memory.readUtf8String(dataPtr, Math.min(dataLen, 1024));
                            if (text.length > 10) {
                                console.log("\n文本内容:");
                                console.log(text.substring(0, 500));
                            }
                        } catch (e) {
                            // 不是文本数据
                        }
                        
                        // 保存原始数据（前1024字节）
                        var saveLen = Math.min(dataLen, 1024);
                        var dataToSave = Memory.readByteArray(dataPtr, saveLen);
                        saveToFile("shumei_keys.txt", "数据: " + bufferToHex(dataToSave));
                    }
                } catch (e) {
                    console.log("[-] 读取数据失败: " + e);
                }
                
                this.timestamp = Date.now();
            },
            onLeave: function(retval) {
                var elapsed = Date.now() - this.timestamp;
                console.log("\n✅ AES加密完成（耗时 " + elapsed + "ms）");
                console.log("返回值: " + retval);
                
                saveToFile("shumei_keys.txt", "=".repeat(80) + "\n");
                console.log("=".repeat(80) + "\n");
            }
        });
    } catch (e) {
        console.log("[-] Hook AES函数失败: " + e);
    }
    
    // ========== Hook 2: zlib deflate初始化 ==========
    try {
        // deflateInit2_ 通常在 SO 中有导出
        var deflateInit = Module.findExportByName("libsmsdk.so", "deflateInit2_");
        if (deflateInit) {
            console.log("[+] Hook deflateInit2_: " + deflateInit);
            
            Interceptor.attach(deflateInit, {
                onEnter: function(args) {
                    var level = args[1].toInt32();
                    var method = args[2].toInt32();
                    var windowBits = args[3].toInt32();
                    var memLevel = args[4].toInt32();
                    var strategy = args[5].toInt32();
                    
                    console.log("\n" + "-".repeat(80));
                    console.log("【zlib压缩】初始化");
                    console.log("  压缩级别: " + level);
                    console.log("  方法: " + method);
                    console.log("  windowBits: " + windowBits);
                    console.log("  内存级别: " + memLevel);
                    console.log("  策略: " + strategy);
                    console.log("-".repeat(80));
                }
            });
        }
    } catch (e) {
        console.log("[-] Hook deflateInit2_失败: " + e);
    }
    
    // ========== Hook 3: Base64编码 (sub_465D0) ==========
    try {
        var base64_addr = libsmsdk.base.add(0x465D0);
        console.log("[+] Hook Base64编码: " + base64_addr);
        
        Interceptor.attach(base64_addr, {
            onEnter: function(args) {
                console.log("\n" + "-".repeat(80));
                console.log("【Base64编码】调用");
                
                // 第二个参数通常是输入数据指针
                try {
                    var dataPtr = args[1];
                    var dataLen = args[2].toInt32();
                    console.log("  数据长度: " + dataLen + " 字节");
                    console.log("  数据（前64字节）:");
                    console.log(hexdump(dataPtr, {length: Math.min(64, dataLen), ansi: true}));
                } catch (e) {
                    console.log("  无法读取输入数据");
                }
                
                console.log("-".repeat(80));
            },
            onLeave: function(retval) {
                try {
                    var result = Memory.readUtf8String(retval);
                    console.log("  Base64结果（前128字符）:");
                    console.log("  " + result.substring(0, 128) + "...");
                } catch (e) {
                    console.log("  无法读取结果");
                }
            }
        });
    } catch (e) {
        console.log("[-] Hook Base64函数失败: " + e);
    }
    
    // ========== Hook 4: 主入口函数 (sub_8F2C) ==========
    try {
        var entry_addr = libsmsdk.base.add(0x8F2C);
        console.log("[+] Hook 主入口函数: " + entry_addr);
        
        Interceptor.attach(entry_addr, {
            onEnter: function(args) {
                console.log("\n" + "█".repeat(80));
                console.log("【主函数】调用 - 数美SDK开始执行");
                console.log("█".repeat(80));
                
                // JNI参数解析
                console.log("JNIEnv: " + args[0]);
                console.log("jobject: " + args[1]);
                
                // 尝试读取传入的参数（Java字符串）
                for (var i = 2; i < 13; i++) {
                    try {
                        var param = args[i];
                        if (param && !param.isNull()) {
                            console.log("参数 a" + i + ": " + param);
                        }
                    } catch (e) {
                        // 忽略
                    }
                }
                
                this.startTime = Date.now();
            },
            onLeave: function(retval) {
                var elapsed = Date.now() - this.startTime;
                console.log("\n✅ 主函数执行完成（总耗时 " + elapsed + "ms）");
                
                // 尝试读取返回的JSON字符串
                try {
                    var jniEnv = Java.vm.getEnv();
                    var result = jniEnv.getStringUtfChars(retval, null).readCString();
                    console.log("\n📦 返回结果:");
                    console.log(result);
                    
                    // 保存完整结果
                    saveToFile("shumei_response.json", result);
                } catch (e) {
                    console.log("[-] 无法读取返回结果: " + e);
                }
                
                console.log("█".repeat(80) + "\n");
            }
        });
    } catch (e) {
        console.log("[-] Hook 主函数失败: " + e);
    }
    
    // ========== Hook 5: 证书处理函数 (sub_9AF24) ==========
    try {
        var cert_addr = libsmsdk.base.add(0x9AF24);
        console.log("[+] Hook 证书处理函数: " + cert_addr);
        
        Interceptor.attach(cert_addr, {
            onEnter: function(args) {
                console.log("\n" + "-".repeat(80));
                console.log("【证书处理】调用");
                console.log("  参数1: " + args[0]);
                console.log("  参数2: " + args[1]);
                console.log("-".repeat(80));
            }
        });
    } catch (e) {
        console.log("[-] Hook 证书函数失败: " + e);
    }
    
    console.log("\n✅ Hook 安装完成！");
    console.log("💡 提示：");
    console.log("   - 密钥和IV将保存到: /sdcard/shumei_keys.txt");
    console.log("   - 响应结果将保存到: /sdcard/shumei_response.json");
    console.log("   - 请在应用中触发数美SDK调用");
    console.log("   - 使用 'adb pull /sdcard/shumei_keys.txt' 获取结果");
    console.log("\n" + "=".repeat(80) + "\n");
}

// 错误处理
Process.setExceptionHandler(function(details) {
    console.log("\n❌ 异常发生:");
    console.log("  类型: " + details.type);
    console.log("  地址: " + details.address);
    console.log("  内存: " + JSON.stringify(details.memory));
    console.log("  上下文: " + JSON.stringify(details.context));
    return false;  // 继续传递异常
});



